package utils;

import com.yangjicong.o2o.studey.base.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import emun.ToolErrorCode;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Date工具类
 * <p>
 * 1.计算两个时间相差天数
 * 2.字符串转LocalDateTime
 * 3.字符串转LocalDateTime
 * 4.两个date类型相比较
 * 5.判断当前时间是否超过最晚支付时间
 * 6.将String【格式：yyyy-MM-dd HH:mm:ss】类型转换成Date类型
 * 7.将字符串转换成固定格式时间
 * 8、将Date类型转换成 String 【yyyy-MM-dd HH:mm:ss】
 *
 *
 * getNextDate()        获取次日00:00时间
 * getMonthOfDay()      获取本年本月指定日求
 * packingTime()        获取某天某时某分某秒的时间
 * last : 生成随机时间
 * </p>
 *
 * @author by yangjicong;
 * @date 2022/2/8.
 */
@Slf4j
public class DateUtil {

    private DateUtil() {

    }

    /**
     * 存放不同的日期模板格式的sdf的Map
     */
    private static Map<String, ThreadLocal<SimpleDateFormat>> sdfMap = new HashMap<>();
    /**
     * 日期时间格式 *
     */

    public static final String DATE_PATTERN = "yyyyMMdd";
    public static final String FULL_PATTERN = "yyyyMMddHHmmss";
    public static final String FULL_PATTERNS = "yyyyMMddHHmmssSSS";
    public static final String PART_PATTERN = "yyMMddHHmmss";
    public static final String YEAR_DATE = "yyyy-MM-dd HH:mm";
    public static final String DATE_PATTERNS = "yyyy-MM-dd HH:mm:ss:SSS";
    public static final String DATE_PATTERN1 = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_PATTERN2 = "yyyy-MM-dd";
    public static final String DATE_PATTERNz = "yyyy-MM";
    public static final String DATE_PATTERN3 = "HH:mm:ss";
    public static final String DATE_PATTERN31 = "HH:mm";
    public static final String DATE_PATTERN4 = "yyyy.MM.dd";
    /**
     * 日期时间格式：yyyy.MM.dd HH:mm:ss
     */
    public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
    /**
     * 日期时间格式：yyyy-MM-dd
     */
    public static final String YYYY_MM_DD = "yyyy-MM-dd";

    /**
     * 计算两个时间相差天数
     *
     * @param date1
     * @param date2
     */
    public static int daysOfTwo(String date1, String date2, String pattern) {
        long days = -1;
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(pattern);
            //跨年不会出现问题
            //如果时间为：2016-03-18 11:59:59 和 2016-03-19 00:00:01的话差值为 0
            if (StringUtils.isEmpty(date1)) {
                Calendar c = Calendar.getInstance();
                date1 = sdf.format(c.getTime());
            }
            Date fDate = sdf.parse(date1);
            Date oDate = sdf.parse(date2);
            days = (oDate.getTime() - fDate.getTime()) / (1000 * 3600 * 24);
        } catch (Exception e) {
            log.error("时间计算异常：" + e);
        }
        return (int) days;
    }

    public static int daysOfTwo(String date1, String date2) {
        return daysOfTwo(date1, date2, DATE_PATTERN);
    }

    /**
     * 字符串转LocalDateTime
     *
     * @param time
     * @param format
     * @return
     */
    public static LocalDateTime parseStringToLocalDateTime(String time, String format) {
        return parseStringToLocalDateTime(time, DateTimeFormatter.ofPattern(format));
    }

    /**
     * 字符串转LocalDateTime
     *
     * @param time
     * @param formatter
     * @return
     */
    public static LocalDateTime parseStringToLocalDateTime(String time, DateTimeFormatter formatter) {
        return LocalDateTime.parse(time, formatter);
    }


    public static long betweenTwoTime(LocalDateTime startTime, LocalDateTime endTime, ChronoUnit field) {
        Period period = Period.between(LocalDate.from(startTime), LocalDate.from(endTime));
        if (field == ChronoUnit.YEARS) {
            return period.getYears();
        }
        if (field == ChronoUnit.MONTHS) {
            return new Long(period.getYears() * 12 + period.getMonths());
        }
        return field.between(startTime, endTime);
    }

    /**
     * 两个date类型相比较
     * date1>date2  1
     * date1=date2  0
     * date1<date2   -1
     *
     * @param d1
     * @param d2
     * @return
     */

    public static int compareDate(Date d1, Date d2) {
        Calendar c1 = Calendar.getInstance();
        Calendar c2 = Calendar.getInstance();
        c1.setTime(d1);
        c2.setTime(d2);

        int result = c1.compareTo(c2);

        return result;
    }

    /**
     * 判断当前时间是否超过最晚支付时间
     *
     * @param orderFinalPayDatetime 最晚支付时间
     * @return 校验结果
     */
    public static Boolean checkPayFinalDateTime(String orderFinalPayDatetime) {
        Date orderFinalDate = parse(orderFinalPayDatetime);
        Date now = new Date();
        return now.after(orderFinalDate);
    }

    /**
     * 将String【格式：yyyy-MM-dd HH:mm:ss】类型转换成Date类型
     *
     * @param date 格式：yyyy-MM-dd HH:mm:ss
     * @return Date
     */
    public static Date parse(String date) {
        if (null != date && date.length() > 14) {
            return parseTo(date, YYYY_MM_DD_HH_MM_SS);
        }
        return parseTo(date, YYYY_MM_DD);
    }

    /**
     * 将String【格式：yyyy-MM-dd HH:mm:ss】类型转换成Date类型
     *
     * @param date 格式：yyyy-MM-dd HH:mm:ss
     * @return Date
     */
    public static Date parseZero(String date) {
        if (null != date && date.length() > 14) {
            return parseTo(date, DATE_PATTERNS);
        }
        return parseTo(date, YYYY_MM_DD);
    }

    /**
     * 将String【格式：yyyy-MM-dd HH:mm:ss】类型转换成Date类型
     *
     * @param date 格式：yyyy-MM-dd HH:mm:ss
     * @return Date
     */
    public static Date parseFromInt(String date) {
        if (null != date && date.length() > 14) {
            return parseTo(date, FULL_PATTERN);
        }
        return parseTo(date, FULL_PATTERN);
    }


    /**
     * @param d1
     * @param d2
     * @return d1 >= da2 返回true
     */
    public static boolean compareDateBool(Date d1, Date d2) {
        return compareDate(d1, d2) >= 0;
    }

    /**
     * 将字符串转换成固定格式时间
     *
     * @param date    日期
     * @param pattern 自定义格式
     * @return 转换后日期
     */
    public static Date parseTo(String date, String pattern) {

        DateTime dateTime = parseTime(date, pattern);
        if (dateTime == null) {
            return null;
        }
        return dateTime.toDate();
    }

    /**
     * 将字符串转换成固定格式时间
     *
     * @param date    日期
     * @param pattern 自定义格式
     * @return 转换后日期
     */
    public static DateTime parseTime(String date, String pattern) {
        return DateTimeFormat.forPattern(pattern).parseDateTime(date);
    }

    /**
     * 8、将Date类型转换成 String 【yyyy-MM-dd HH:mm:ss】
     *
     * @param date 时间
     * @return String
     */
    public static String format(Date date) {
        return format(date, YYYY_MM_DD_HH_MM_SS);
    }

    /**
     * 将Date类型按照固定的模式转换 String
     *
     * @param date    时间
     * @param pattern 格式
     * @return String
     */
    public static String format(Date date, String pattern) {
        if (date == null) {
            return null;
        }
        return new DateTime(date).toString(pattern);
    }


    /**
     * 获取当前时间
     *
     * @return
     */
    public static String getCurrent() {
        //设置日期格式
        SimpleDateFormat df = new SimpleDateFormat(DateUtil.FULL_PATTERN);
        return df.format(new Date());
    }

    /**
     * 获取当前时间
     *
     * @return
     */
    public static String getCurrent(String pattern) {
        //设置日期格式
        SimpleDateFormat df = new SimpleDateFormat(pattern);
        return df.format(new Date());
    }

    /**
     * 23、获取当前时间
     *
     * @return Date
     */
    public static Date getCurrentDate() {
        return new Date();
    }

    /**
     * 获取天数差值
     *
     * @param beginDateStr 开始日期
     * @param endDateStr   结束日期
     * @return 天数
     */

    public static long getDay(String beginDateStr, String endDateStr) {
        SimpleDateFormat format = new SimpleDateFormat(DATE_PATTERN);
        Date beginDate;
        Date endDate;
        try {
            beginDate = format.parse(beginDateStr);
            endDate = format.parse(endDateStr);

            long day = (endDate.getTime() - beginDate.getTime()) / (24 * 60 * 60 * 1000);
            return day + 1;
        } catch (ParseException e) {
            log.error("获取日期差值异常！");

            throw new BusinessException(ToolErrorCode.GET_DAY_ERR.getCode(), ToolErrorCode.GET_DAY_ERR.getDesc());
        }
    }

    /**
     * String转Date
     *
     * @param
     * @throws ParseException
     */
    public static Date stringToDate(String str, String pattern) {
        DateFormat format = new SimpleDateFormat(pattern);
        Date date = null;
        try {
            date = format.parse(str);
        } catch (ParseException e) {
            log.error("ParseException e:{}", e);
        }
        return date;
    }

    /**
     * 时间格式转换
     *
     * @param date    时间字符串
     * @param pattern 新的时间格式
     * @return
     * @throws ParseException
     */

    public static String dateToStrLong(Date date, String pattern) {
        if (Objects.isNull(date)) {
            return StringUtils.EMPTY;
        }
        SimpleDateFormat formatter = new SimpleDateFormat(pattern);
        String dateString = formatter.format(date);
        return dateString;
    }

    /**
     * date1小于date2返回-1，date1大于date2返回1，相等返回0
     *
     * @param date2
     * @return
     */
    public static int contrastDate(Date date2) {
        SimpleDateFormat sf = new SimpleDateFormat(FULL_PATTERN);
        Calendar c = Calendar.getInstance();
        c.add(Calendar.DAY_OF_MONTH, 0);
        Date d1 = stringToDate(sf.format(c.getTime()), FULL_PATTERN);
        if (d1 == null) {
            return 0;
        }
        return d1.compareTo(date2);
    }

    /**
     * date1小于date2返回-1，date1大于date2返回1，相等返回0
     *
     * @param date2
     * @return
     */
    public static int contrastDate(String date2) {
        SimpleDateFormat sf = new SimpleDateFormat(FULL_PATTERN);
        Calendar c = Calendar.getInstance();
        c.add(Calendar.DAY_OF_MONTH, 0);
        Date d1 = stringToDate(sf.format(c.getTime()), FULL_PATTERN);
        if (d1 == null) {
            return 0;
        }
        Date d2 = stringToDate(date2, FULL_PATTERN);
        return d1.compareTo(d2);
    }

    /**
     * 源日期和（目标日期加上毫秒数）比较大小， 大则返回false ，小返回true
     *
     * @param src    源日期
     * @param target 目的日期
     * @param second 秒数
     * @return 成功，失败
     */
    public static boolean compareDateForSecond(Date src, Date target, int second) {
        Calendar targetTime = Calendar.getInstance();
        targetTime.setTime(target);
        targetTime.add(Calendar.SECOND, second);
        Calendar srcTime = Calendar.getInstance();
        srcTime.setTime(src);
        return srcTime.compareTo(targetTime) <= 0;
    }

    /**
     * 获取count分钟前的时间
     *
     * @param count
     * @return
     */
    public static Date getDateMin(int count) {
        Calendar beforeTime = Calendar.getInstance();
        // 5分钟之前的时间
        beforeTime.add(Calendar.MINUTE, count);
        return beforeTime.getTime();
    }


    /**
     * 将任意时间格式转换为2019年1月1日
     *
     * @param dateTime
     * @return
     */
    public static String getDatePattern(Date dateTime) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
        String str = sdf.format(dateTime);
        return str;
    }

    /**
     * 将任意时间格式转换为2019年1月1日
     *
     * @param dateTime
     * @param partPattern
     * @return
     */
    public static String getDatePattern(String dateTime, String partPattern, String pattern) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        SimpleDateFormat sdf1 = new SimpleDateFormat(partPattern);
        String str = "";
        try {
            Date date = sdf1.parse(dateTime);

            str = sdf.format(date);
        } catch (ParseException e) {
            log.error("ParseException e:{}", e);
        }
        return str;
    }

    /**
     * 获取开始时间
     *
     * @param date
     * @return
     */
    public static Date getDataStartTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /**
     * 获取结束时间
     *
     * @param date
     * @return
     */
    public static Date getDataEndTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        return calendar.getTime();
    }

    /**
     * 获取几天前的时间
     *
     * @param days
     * @return
     */
    public static Date getDateBefore(int days) {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, -days);
        return cal.getTime();
    }

    /**
     * 日期往后加n天
     *
     * @param n n 正数往后，负数往前
     */
    public static String addDay(String date, String pattern, int n) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(pattern);

            Calendar cal = Calendar.getInstance();
            cal.setTime(sdf.parse(date));
            cal.add(Calendar.DATE, +n);
            return sdf.format(cal.getTime());
        } catch (Exception e) {
            return null;
        }

    }

    /**
     * 日期往后加n
     *
     * @param n n 正数往后，负数往前
     */
    public static String addTime(String date, String pattern, int n, TimeUnit unit) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(pattern);
            Calendar cal = Calendar.getInstance();
            cal.setTime(sdf.parse(date));
            if (TimeUnit.DAYS == unit) {
                cal.add(Calendar.DATE, n);
            }
            if (TimeUnit.HOURS == unit) {
                cal.add(Calendar.HOUR, n);
            }
            if (TimeUnit.MINUTES == unit) {
                cal.add(Calendar.MINUTE, n);
            }
            return sdf.format(cal.getTime());
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * addDate
     *
     * @param date          date
     * @param calendarField calendarField
     * @param amount        amount
     * @return java.util.Date
     * @author 张凯
     * @date 2021/10/30 19:21
     */
    private static Date addDate(Date date, int calendarField, int amount) {
        if (date == null) {
            throw new IllegalArgumentException("The date could not be null!");
        }
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(calendarField, amount);
        return c.getTime();
    }


    /**
     * @param date   时间
     * @param minute 变化的分数
     * @return 操作后结果
     */
    public static Date addMinute(Date date, int minute) {
        return addDate(date, Calendar.MINUTE, minute);
    }

    public static String formatDate(Date date) {
        if (null == date) {
            return null;
        }
        return format(date, FULL_PATTERN);
    }

    /**
     * 获取本周几
     *
     * @param week 本周几
     * @return
     */
    public static Date getWeekOfDate(int week) {
        Calendar cal = Calendar.getInstance();
        // 设置第一天
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        // 当前第几天
        int day = cal.get(Calendar.DAY_OF_WEEK);
        // 获取第一天
        int firstDayOfWeek = cal.getFirstDayOfWeek();
        // 获取本周几week
        cal.add(Calendar.DATE, firstDayOfWeek - day + week);
        return getDataStartTime(cal.getTime());
    }

    /**
     * 获取次日00:00时间
     *
     * @return
     */
    public static Date getNextDate() {
        Calendar ca = Calendar.getInstance();
        ca.set(Calendar.HOUR_OF_DAY, 0);
        ca.set(Calendar.MINUTE, 0);
        ca.set(Calendar.SECOND, 0);
        ca.set(Calendar.MILLISECOND, 0);
        ca.add(Calendar.DAY_OF_MONTH, 1);
        ca.add(Calendar.MILLISECOND, 0);
        return ca.getTime();
    }

    /**
     * 获取本年本月指定日求
     *
     * @param localDate
     * @param dayOfMonth
     * @return
     */
    public static String getMonthOfDay(LocalDate localDate, int dayOfMonth) {
        return localDate.withDayOfMonth(dayOfMonth).format(DateTimeFormatter.ofPattern(DATE_PATTERN2));
    }

    /**
     * description:获取某天某时某分某秒的时间
     *
     * @date: 2022/03/09
     */
    public static String packingTime(Integer day, Integer hour, Integer minute, Integer second) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(new Date());
        calendar.add(Calendar.DATE, day);
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);
        Date newUnpackingTime = calendar.getTime();
        return dateFormatyMdHms(newUnpackingTime);
    }


    public static String dateFormatyMdHms(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(date);
    }

    public static void main(String[] args) {
        //Date date = randomDate("2022-10-01","2022-11-01");
        //
        //SimpleDateFormat format = new SimpleDateFormat(DATE_PATTERNS);
        //String regulative = format.format(date);//构造开始日期
        //tim();
        //System.out.println("regulative = " + regulative);

        //tim();
        isToday(new Date());

        //System.out.println(getSecondsNextEarlyMorning());
        //
        //String current = DateUtil.getCurrent(DateUtil.DATE_PATTERN2);
        //System.out.println("current = " + current);
        //
        ////测试时间1
        //String testTimeOne = "2018-07-31 10:25:11";
        ////测试时间2
        //String testTimeTwo = "2022-07-28 13:09:51";
        ////时间格式化
        //SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //Date psTestTimeOne = null;
        //Date psTestTimeTwo = null;
        //try {
        //    psTestTimeOne = format.parse(testTimeOne);
        //    psTestTimeTwo = format.parse(testTimeTwo);
        //} catch (ParseException e) {
        //    e.printStackTrace();
        //}
        //boolean today = isToday(psTestTimeOne);
        //boolean today1 = isToday(psTestTimeTwo);
        //System.out.println("测试时间输出为true，则处于当天24h范围内，false反之。");
        //System.out.println("测试时间一："+today);
        //System.out.println("测试时间二："+today1);

    }

    /**
     * @Description 是否为当天24h内
     * @author 刘鹏博
     * @param inputJudgeDate 要判断是否在当天24h内的时间
     * @return
     * boolean
     */
    public static boolean isToday(Date inputJudgeDate) {
        boolean flag = false;
        //获取当前系统时间
        long longDate = System.currentTimeMillis();
        Date nowDate = new Date(longDate);
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = dateFormat.format(nowDate);
        System.out.println("format = " + format);
        String subDate = format.substring(0, 10);
        //定义每天的24h时间范围
        String beginTime = subDate + " 00:00:00";
        String endTime = subDate + " 23:59:59";
        Date paseBeginTime = null;
        Date paseEndTime = null;
        try {
            paseBeginTime = dateFormat.parse(beginTime);
            paseEndTime = dateFormat.parse(endTime);

        } catch (ParseException e) {
            log.error(e.getMessage());
        }
        if(inputJudgeDate.after(paseBeginTime) && inputJudgeDate.before(paseEndTime)) {
            flag = true;
        }
        return flag;
    }

    /**
     * 获取当前时间到凌晨的描述
     * @return
     */
    public static Long getSecondsNextEarlyMorning() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DAY_OF_YEAR, 1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return (cal.getTimeInMillis() - System.currentTimeMillis()) / 1000;
    }

    public static void tim(){


        //获取随机日期
        for (int i = 0; i < 10000000; i++) {
            Date randomDate=randomDate("2020-09-20","2025-02-04");
            SimpleDateFormat format = new SimpleDateFormat(DATE_PATTERN2);
            //构造开始日期
            String regulative = format.format(randomDate);
            //System.out.println("过期日期为"+regulative);

            //自定义日期
            String myTime = "2022-07-01";
            LocalDate ex = LocalDate.parse(myTime, DateTimeFormatter.ofPattern(DATE_PATTERN2));

            System.out.println("ex = " + ex.compareTo(LocalDate.now().with(TemporalAdjusters.firstDayOfMonth())));
            System.out.println(" ========================= " );
            if (ex.compareTo(LocalDate.now().with(TemporalAdjusters.firstDayOfMonth())) < 0) {
                System.out.println("商户号失效，失败");

            } else {

                System.out.println("商户号未失效，走正常逻辑");
            }
        }

    }

    /**
     * 生成随机时间
     * @param beginDate
     * @param endDate
     * @return
     */
    private static Date randomDate(String beginDate,String endDate ){

        try {

            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

            Date start = format.parse(beginDate);//构造开始日期

            Date end = format.parse(endDate);//构造结束日期

            //getTime()表示返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。

            if(start.getTime() >= end.getTime()){

                return null;

            }

            long date = random(start.getTime(),end.getTime());

            return new Date(date);

        } catch (Exception e) {

            e.printStackTrace();

        }

        return null;

    }

    private static long random(long begin,long end){

        long rtn = begin + (long)(Math.random() * (end - begin));

        //如果返回的是开始时间和结束时间，则递归调用本函数查找随机值

        if(rtn == begin || rtn == end){

            return random(begin,end);

        }

        return rtn;

    }






    public static void testDate() {
        String monthOfDay = getMonthOfDay(LocalDate.now(), 26);
        System.out.println("monthOfDay = " + monthOfDay);

        System.out.println("stringToDate(monthOfDay,DATE_PATTERN2) = " + stringToDate(monthOfDay, DATE_PATTERN2));

        LocalDate parse = LocalDate.parse(monthOfDay, DateTimeFormatter.ofPattern(DATE_PATTERN2));
        LocalDate parse1 = LocalDate.parse("2022-05-28", DateTimeFormatter.ofPattern(DATE_PATTERN2));
        System.out.println("parse1 = " + parse1.getMonthValue());
        int i = parse.compareTo(parse1);

        // 判断parse是否在parse1之前，返回布尔值
        boolean before = parse.isBefore(parse1);
        System.out.println("判断localDate1是否在localDate2之前：" + before);
        System.out.println("i = " + i);
        System.out.println("parse = " + parse);

    }

}

